/**
 *    Copyright 2009-2019 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.reflection;

import java.lang.reflect.*;
import java.util.Arrays;

/**
 * 泛型参数解析器
 *
 * @author Iwao AVE!
 */
public class TypeParameterResolver {

    /**
     * 获取指定字段的实际类型，将泛型转换为实际类型
     *
     * @param field   字段
     * @param srcType 运行时字段所属对象类型
     * @return 如果field在声明的时候有泛型定义，这些泛型会被解析会运行时的实际类型
     */
    public static Type resolveFieldType(Field field, Type srcType) {
        // 获取字段的类型
        Type fieldType = field.getGenericType();
        // 获取声明字段的类
        Class<?> declaringClass = field.getDeclaringClass();
        // 执行解析操作
        return resolveType(fieldType, srcType, declaringClass);
    }

    /**
     * 获取指定方法的返回类型，将泛型转换为实际类型
     *
     * @param method  方法
     * @param srcType 运行时方法所属对象类型
     * @return 如果方法返回值在声明的时候有泛型定义，这些泛型会被解析会运行时的实际类型
     */
    public static Type resolveReturnType(Method method, Type srcType) {
        // 获取方法返回类型
        Type returnType = method.getGenericReturnType();
        // 获取声明该方法的对象的类型
        Class<?> declaringClass = method.getDeclaringClass();
        return resolveType(returnType, srcType, declaringClass);
    }

    /**
     * 获取指定方法的所有入参的实际类型，将泛型转换为实际类型
     *
     * @param method  方法
     * @param srcType 通过反射获取该方法的类的类型
     * @return 如果方法入参在声明的时候有泛型定义，这些泛型会被解析会运行时的实际类型
     */
    public static Type[] resolveParamTypes(Method method, Type srcType) {
        // 获取所有方法入参
        Type[] paramTypes = method.getGenericParameterTypes();
        // 声明该方法的类
        Class<?> declaringClass = method.getDeclaringClass();
        Type[] result = new Type[paramTypes.length];
        // 依次处理
        for (int i = 0; i < paramTypes.length; i++) {
            result[i] = resolveType(paramTypes[i], srcType, declaringClass);
        }
        return result;
    }

    /**
     * 将指定类型中的泛型定义转换为运行时的实际类型定义
     *
     * @param type           可能包含泛型定义的类型
     * @param srcType        运行期间该类型所属的实例对象
     * @param declaringClass 声明了type定义的类
     * @return 指定类型处理完泛型定义后的类型
     */
    private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
        if (type instanceof TypeVariable) {
            // 解析类型参数，比如: 泛型参数表示具体的某一独立的类型
            return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
        } else if (type instanceof ParameterizedType) {
            // 解析参数化的泛型，比如:List<T> list;
            return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
        } else if (type instanceof GenericArrayType) {
            // 解析泛型数组,比如: List<N>[] listArray;
            return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
        } else {
            // 普通类型(Class)直接返回
            return type;
        }
    }

    private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
        // 获取数组泛型中元素的泛型类型，比如: T[] testArray中T的类型
        Type componentType = genericArrayType.getGenericComponentType();

        // 解析元素的泛型类型
        Type resolvedComponentType = null;
        if (componentType instanceof TypeVariable) {
            // 解析泛型变量:Class<A extends B>
            resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
        } else if (componentType instanceof GenericArrayType) {
            // 递归解析泛型数组:List<N>[] listArray;
            resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
        } else if (componentType instanceof ParameterizedType) {
            // 解析参数化泛型:List<T> list
            resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
        }

        // 将解析出的泛型类型转换为数组类型
        if (resolvedComponentType instanceof Class) {
            return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
        } else {
            // 解析出来泛型的实际类型还是一个泛型定义
            return new GenericArrayTypeImpl(resolvedComponentType);
        }
    }

    /**
     * 解析参数化泛型的实际类型
     *
     * @param parameterizedType 泛型类型
     * @param srcType           运行期间该类型所属的实例对象
     * @param declaringClass    声明了parameterizedType定义的类
     */
    private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
        // 获取参数化泛型中的原始类比如:List<E>中的E
        Class<?> rawType = (Class<?>) parameterizedType.getRawType();
        // 获取实际泛型实参列表，比如List<String>会得到[String]。
        Type[] typeArgs = parameterizedType.getActualTypeArguments();
        // 声明参数集合
        Type[] args = new Type[typeArgs.length];

        // 依次处理泛型参数的实际类型,比如Map<K,V>,依次获取K和V的实际类型
        for (int i = 0; i < typeArgs.length; i++) {
            if (typeArgs[i] instanceof TypeVariable) {
                // 解析泛型变量使用resolveTypeVar方法：比如:Class<A extends B>获取A和B的类型
                args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
            } else if (typeArgs[i] instanceof ParameterizedType) {
                // 解析泛型参数使用resolveParameterizedType方法，比如:List<T> list;
                args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
            } else if (typeArgs[i] instanceof WildcardType) {
                // 解析通配符表达式形式的泛型，比如:List<? extends N> list;
                args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
            } else {
                // 普通的Class类型直接返回
                args[i] = typeArgs[i];
            }
        }
        // 重新包装成ParameterizedType返回
        return new ParameterizedTypeImpl(rawType, null, args);
    }

    private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
        // 获取通配符泛型对应的类型下限
        Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);

        // 获取通配符泛型对应的类型上限
        Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);

        // 包装通配符泛型实现
        return new WildcardTypeImpl(lowerBounds, upperBounds);
    }

    /**
     * @param bounds         类型边界
     * @param srcType        泛型变量所属类
     * @param declaringClass 泛型变量声明类
     */
    private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
        Type[] result = new Type[bounds.length];
        // 依次处理泛型边界中的每个具体的泛型定义
        for (int i = 0; i < bounds.length; i++) {
            if (bounds[i] instanceof TypeVariable) {
                // 处理泛型变量
                result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
            } else if (bounds[i] instanceof ParameterizedType) {
                // 处理参数化泛型
                result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
            } else if (bounds[i] instanceof WildcardType) {
                // 递归处理通配符泛型,我脑海里暂时想不出来什么时候会执行这一行代码
                // 如果有人知道的话，麻烦在您方便的情况下，告知我，谢谢了~
                // 我的邮箱: jpanda@aliyun.com
                result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
            } else {
                // 普通Class
                result[i] = bounds[i];
            }
        }
        return result;
    }

    /**
     * 解析指定泛型变量的类型
     *
     * @param typeVar        泛型变量
     * @param srcType        用于获取泛型变量实际类型的类
     * @param declaringClass 实际声明该类型的类的类型
     */
    private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {

        Type result = null;
        Class<?> clazz = null;
        // step1: 处理srcType，移除泛型定义，获取对应的Class类型
        if (srcType instanceof Class) {
            clazz = (Class<?>) srcType;
        } else if (srcType instanceof ParameterizedType) {
            // 泛型参数取声明泛型的类型
            ParameterizedType parameterizedType = (ParameterizedType) srcType;
            clazz = (Class<?>) parameterizedType.getRawType();
        } else {
            // 理论上讲不会出现其他的类型场景
            throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
        }

        // step2: 获取泛型定义的实际类型

        // case1: 当前类就是声明了泛型的类
        if (clazz == declaringClass) {
            //  当前类就是声明了泛型的类，则泛型一定未被指定具体类型，获取泛型变量类型上限
            Type[] bounds = typeVar.getBounds();
            if (bounds.length > 0) {
                return bounds[0];
            }

            // 没有指定泛型变量上限，那就是Object。
            return Object.class;
        }

        // case2: 尝试从父类中获取泛型变量的实际类型

        // 运行期间泛型所属的对象和声明泛型定义的不是同一个
        // 获取其直接父类类型，尝试从父类中找到泛型定义
        Type superclass = clazz.getGenericSuperclass();
        // 递归处理父类，直到找到该泛型对应的实际类型，或者null值。
        result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
        if (result != null) {
            return result;
        }

        // case3: 无法通过父类获取泛型变量的实际类型,则通过接口定义获取泛型变量对应的实际类型

        // 获取类实现的所有接口，尝试从接口中获取泛型变量的定义
        Type[] superInterfaces = clazz.getGenericInterfaces();
        for (Type superInterface : superInterfaces) {
            result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
            if (result != null) {
                return result;
            }
        }
        // 在接口中也未找到泛型变量的实际类型，返回Object类型。
        return Object.class;
    }

    /**
     * @param typeVar        泛型变量的类型
     * @param srcType        泛型变量所属对象的类
     * @param declaringClass 声明泛型变量的类
     * @param clazz          泛型变量所属对象处理泛型后的类型
     * @param superclass     srcType直接父类或者接口
     */
    private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
        // 针对父类的类型定义有三种处理方案
        // 1.参数化泛型
        // 2.普通类同时是声明了泛型的类的实现
        // 3.普通类但不是声明了泛型实现的类的实现

        if (superclass instanceof ParameterizedType) {
            // case1：参数化泛型定义类

            ParameterizedType parentAsType = (ParameterizedType) superclass;
            // 获取父类除去泛型定义之后的类型
            Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
            // 获取父类中的泛型定义
            TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();

            // 泛型变量所属对象的类也是一个泛型对象
            if (srcType instanceof ParameterizedType) {
                // 合并子类和父类的泛型定义比如: Super<A,B>{},Sub extend Super<String,Integer>.
                parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
            }

            if (declaringClass == parentAsClass) {
                // 父类就是声明了泛型变量的类
                for (int i = 0; i < parentTypeVars.length; i++) {
                    // 找到了typeVar对应的实际类型定义
                    if (typeVar == parentTypeVars[i]) {
                        // 返回泛型的实际类型
                        return parentAsType.getActualTypeArguments()[i];
                    }
                }
            }

            if (declaringClass.isAssignableFrom(parentAsClass)) {
                // 父类是声明了泛型类的子类，继续递归查找
                return resolveTypeVar(typeVar, parentAsType, declaringClass);
            }
        } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
            // case2: 父类是一个普通的类，同时父类是泛型变量所属定义类的子实现
            // 递归
            return resolveTypeVar(typeVar, superclass, declaringClass);
        }
        // 父类不是泛型类，同时父类不是泛型变量声明类的实现
        return null;
    }

    private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
        // 获取父类定义的泛型变量的实际类型数组
        Type[] parentTypeArgs = parentType.getActualTypeArguments();
        // 获取子类定义的泛型变量的实际类型数组
        Type[] srcTypeArgs = srcType.getActualTypeArguments();
        // 获取子类中的泛型变量定义
        TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();

        // 父类泛型实参数组
        Type[] newParentArgs = new Type[parentTypeArgs.length];
        boolean noChange = true;
        for (int i = 0; i < parentTypeArgs.length; i++) {
            if (parentTypeArgs[i] instanceof TypeVariable) {
                // 泛型变量
                for (int j = 0; j < srcTypeVars.length; j++) {
                    if (srcTypeVars[j] == parentTypeArgs[i]) {
                        // 子类泛型定义和父类泛型定义一致,则子类中泛型变量的实参对应着父类泛型变量的实参
                        noChange = false;
                        // 从子类中取出泛型变量的实际类型
                        newParentArgs[i] = srcTypeArgs[j];
                    }
                }
            } else {
                // 父类中指定了泛型对应的实际类型
                newParentArgs[i] = parentTypeArgs[i];
            }
        }
        // 合并子类和父类的泛型定义
        return noChange ? parentType
                : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
    }

    private TypeParameterResolver() {
        super();
    }

    static class ParameterizedTypeImpl implements ParameterizedType {
        private Class<?> rawType;

        private Type ownerType;

        private Type[] actualTypeArguments;

        public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
            super();
            this.rawType = rawType;
            this.ownerType = ownerType;
            this.actualTypeArguments = actualTypeArguments;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return actualTypeArguments;
        }

        @Override
        public Type getOwnerType() {
            return ownerType;
        }

        @Override
        public Type getRawType() {
            return rawType;
        }

        @Override
        public String toString() {
            return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments=" + Arrays.toString(actualTypeArguments) + "]";
        }
    }

    static class WildcardTypeImpl implements WildcardType {
        private Type[] lowerBounds;

        private Type[] upperBounds;

        WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
            super();
            this.lowerBounds = lowerBounds;
            this.upperBounds = upperBounds;
        }

        @Override
        public Type[] getLowerBounds() {
            return lowerBounds;
        }

        @Override
        public Type[] getUpperBounds() {
            return upperBounds;
        }
    }

    static class GenericArrayTypeImpl implements GenericArrayType {
        private Type genericComponentType;

        GenericArrayTypeImpl(Type genericComponentType) {
            super();
            this.genericComponentType = genericComponentType;
        }

        @Override
        public Type getGenericComponentType() {
            return genericComponentType;
        }
    }
}
